//
// MDrawer.java
//
package com.photoexpert;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;

class MDrawer implements MouseListener, MouseMotionListener {

    enum METHODS {
        NONE,
        COLOR_PICKER,
        LINE,
        RECT,
        OVAL,
        FILL
    }

    static MDrawer Instance() {
        if(_instance == null) {
            _instance = new MDrawer();
            Presentor.Instance().addMouseListener(_instance);
            Presentor.Instance().addMouseMotionListener(_instance);
        }
        return _instance;
    }

    void reset() {
        _presentor.setCursor(Cursors._handCursor);
        _backuped = false;
    }

    void setColor(Color c) { _color = c; }

    Color getColor() { return _color; }

    void setMethod(METHODS method) {
        _method = method;
    }

    METHODS getMethod() { return _method; }

    void setDialog(DrawerDialog dlg) {
        _dialog = dlg;
    }

    void paint(Graphics g) {
        if(_x1 < 0 || _y1 < 0 || _x2 < 0 || _y2 < 0)
            return;
        g.setColor(_color);
        switch(_method) {
            case LINE :
                g.drawLine(_x1, _y1, _x2, _y2);
                break;
            case RECT :
                g.fillRect(_x1, _y1, _x2 - _x1, _y2 - _y1);
                break;
            case OVAL :
                g.fillOval(_x1, _y1, _x2 - _x1, _y2 - _y1);
                break;
        }
    }

    // MouseListener

    @Override
    public void mouseClicked(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.DRAWING
            || _method == METHODS.NONE)
            return;
        if(_method == METHODS.FILL) {
            int x = e.getX();
            int y = e.getY();
            double rate = _presentor.getZoomRate();
            x = (int)(x / rate);
            y = (int)(y / rate);
            _implementor.fillExpand(x, y, _color);
        } else if(_method == METHODS.COLOR_PICKER) {
            int x = e.getX();
            int y = e.getY();
            double rate = _presentor.getZoomRate();
            x = (int)(x / rate);
            y = (int)(y / rate);
            _logger.log(Level.INFO, "Color picker at {0} {1}", new Object[]{x, y});
            BufferedImage img = _implementor.getImage();
            int rgb = img.getRGB(x, y);
            int r = (rgb & 0x00ff0000) >> 16;
            int g = (rgb & 0x0000ff00) >> 8;
            int b = rgb & 0x000000ff;
            _color = new Color(r, g, b);
            if(_dialog != null)
                _dialog.colorChanged();
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.DRAWING
            || _method == METHODS.NONE)
            return;
        _x1 = e.getX();
        _y1 = e.getY();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.DRAWING
            || _method == METHODS.NONE)
            return;
        if(!_backuped) {
            _implementor.backup();
            _backuped = true;
        }
        double rate = _presentor.getZoomRate();
        int x1 = (int)(_x1 / rate);
        int y1 = (int)(_y1 / rate);
        int x2 = (int)(_x2 / rate);
        int y2 = (int)(_y2 / rate);
        BufferedImage img = _implementor.getImage();
        Graphics g = img.createGraphics();
        g.setColor(_color);
        switch(_method) {
            case LINE :
                g.drawLine(x1, y1, x2, y2);
                break;
            case RECT :
                g.fillRect(x1, y1, x2 - x1, y2 - y1);
                break;
            case OVAL :
                g.fillOval(x1, y1, x2 - x1, y2 - y1);
                break;
        }
        g.dispose();
        _presentor.repaint(0, _x1, _y1, _x2 - _x1, _y2 - _y1);
        _x1 = -1;
        _x2 = -1;
        _y1 = -1;
        _y2 = -1;
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.DRAWING
            || _method == METHODS.NONE)
            return;
    }

    @Override
    public void mouseExited(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.DRAWING
            || _method == METHODS.NONE)
            return;
    }

    // MouseMotionListener

    @Override
    public void mouseDragged(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.DRAWING
            || _method == METHODS.NONE)
            return;
        int x2 = _x2;
        int y2 = _y2;
        _x2 = e.getX();
        _y2 = e.getY();
        x2 = Math.max(x2, _x2);
        y2 = Math.max(y2, _y2);
        _presentor.repaint(_x1, _y1, x2, y2);
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.DRAWING
            || _method == METHODS.NONE)
            return;
    }

    /* ---------------------------------------------------------------- */

    private MDrawer() {
        _presentor = Presentor.Instance();
        _implementor = Implementor.Instance();
    }

    private static MDrawer  _instance = null;
    private final static Logger _logger = App._logger;
    private Presentor           _presentor = null;
    private Implementor         _implementor = null;
    private Color               _color = Color.BLACK;
    private METHODS             _method = METHODS.NONE;
    private DrawerDialog        _dialog = null;
    private int                 _x1 = -1;
    private int                 _y1 = -1;
    private int                 _x2 = -1;
    private int                 _y2 = -1;
    private boolean             _backuped = false;
}
